package Core::MetaMap;

use strict;
use warnings;
use vars qw{ @ISA @EXPORT };
use Exporter;

use Core::Meta;
use Core::List;
use Core::ListIterator;

@ISA = qw( Core::List );
@EXPORT = qw (
   MetaMap
);


sub MetaMap
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{
    my $rhGList = Core::MetaMap->new( @_ );
	return 	$rhGList;
}

sub new
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{
	my( $rhClass ) = shift;               # Object    
    my( $rhSelf ) = {};
    bless( $rhSelf, $rhClass);
    
	my( $raNameList )    =   shift; 
    if( $raNameList and @{ $raNameList } ){
		$rhSelf->init();
		$rhSelf->add( @{ $raNameList } );
	}

    return $rhSelf;
}


sub setList
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{
	my( $rhSelf ) = shift; 	
	# The list that contain the meta object
	my $raMetaList = shift;
	return 0 if not defined $raMetaList;
	
	$rhSelf->{ LIST } = $raMetaList;
	$rhSelf->__calIndex( 1 ) ;

	return 1;	
}

sub init
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{
	my( $rhSelf ) = shift; 
	$rhSelf->{ LIST } = []; 
	$rhSelf->{ INDEX } = {};
	$rhSelf->selected();
}


sub __calIndex
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{
	my( $rhSelf ) = shift; 
	my $sClearUp = shift;
    my $sIndex = 0;
    my $sMetaName;
    
	$rhSelf->{ INDEX } = {} if( $sClearUp );
    foreach my $rhMeta ( @{ $rhSelf->{ LIST } }){
		$sMetaName = $rhMeta->getName();
        $rhSelf->{ INDEX }{ $sMetaName } = $sIndex++;
    }	
	
	return 1;
}

sub index
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{
	my( $rhSelf ) = shift; 
	my $sName = shift;
	
	# Not found
	return -1 if not defined $sName or 
				 not $rhSelf->{ INDEX };	
	
	# Meta name
	$sName = uc( $sName );
	
	# Search and get index 
	return $rhSelf->{ INDEX }{ $sName } 
	            if exists $rhSelf->{ INDEX }{ $sName };
	# Not found
	return -1;
}

sub search
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 
	my( $rhSelf ) = shift;
	my( $sName ) = shift;
	
	# Get the index 
	my $sIndex = $rhSelf->index( $sName ); 
	$sIndex != -1 ? $rhSelf->{ LIST }[ $sIndex ] : 0;
}

sub assert
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 
	my( $rhSelf ) = shift;
	my( $sName ) = shift;
	
	# Get the index 
	my $sIndex = $rhSelf->index( $sName ); 
	if( $sIndex == -1 ){
		$rhSelf->add( $sName );
	}
	
	return $rhSelf->search( $sName );
}


sub exist
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 
	my( $rhSelf ) = shift;
	my( $sName ) = shift;
	my $sIndex = $rhSelf->index( $sName );
	$sIndex != -1 ? 1 : 0;
}

sub add
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 
	my( $rhSelf ) = shift;
	my( $rhMeta );
	foreach my $sName ( @_ ){
		# New meta found
		if ( not $rhSelf->exist( $sName ) ){
			$rhMeta = Meta( $sName ); # Create Meta obj	
			# Only push the meta not in the metalist
			push @{ $rhSelf->{ LIST } }, $rhMeta;
			$rhSelf->__calIndex();	
		}
	}
	return 1;
}

sub pop
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 
	my( $rhSelf ) = shift;
	my( $rhMeta );
	
	if ( $rhSelf->size() > 0 ){
		$rhMeta = pop @{ $rhSelf->{ LIST } } ;
		my $sName = $rhMeta->getName();
		delete $rhSelf->{ INDEX }{ $sName };
	}
	
	$rhMeta ? $rhMeta : 0;
}

sub del
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 
	my ( $rhSelf ) = shift;
	my ( $sIndex ) = shift;
	
	return 0 if not defined $sIndex;
	return 0 if not $rhSelf->del( $sIndex );
	return $rhSelf->__calIndex( 1 );
}	

sub delByName
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 
	my ( $rhSelf ) = shift;
	my ( $sName  ) = shift;
	return 0 if not $sName;
	
	my $sIndex = $rhSelf->index( $sName );
	return 0 if $sIndex == -1;
	return $rhSelf->del( $sIndex );
}	

sub set
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 	my( $rhSelf ) = shift;
	my( $sIndex , $rhMeta ) = @_;
	
	return 0 if not defined $rhMeta; 			
	
	# Update the meta by specific index in metalist
	$rhSelf->{ LIST }[ $sIndex ] = $rhMeta;
	$rhSelf->__calIndex( 1 );
	
	return 1;
}

sub setByName
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 
	my( $rhSelf ) = shift;
	my( $sName, $rhMeta ) = @_;
	
	return 0 if not defined $sName or 
				not defined $rhMeta;
	
	
	my( $sIndex ) = $rhSelf->index( $sName );
	return 0 if $sIndex == -1; # Name not found 
	return $rhSelf->set( $sIndex, $rhMeta );
}

sub getByName
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 
	my ( $rhSelf ) = shift;
	my ( $sName ) = shift;
	
	return $rhSelf->search( $sName );
}

sub getName
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 
	my( $rhSelf ) = shift;
	my( $sIndex ) = shift;
	
	defined $rhSelf->{ LIST }[ $sIndex ] ?
					$rhSelf->{ LIST }[ $sIndex ]->getName() : 0;
}

sub rename
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 
	my( $rhSelf ) = shift;
	my( $sOldName, $sNewName ) = @_;
		
	return 0 if not $sOldName or not $sNewName;
	my $rhMeta = $rhSelf->search( $sOldName );
	return 0 if not $rhMeta;
	
	$rhMeta->setName( $sNewName );
	$rhSelf->__calIndex( 1 );
	
	return $rhMeta;
}	

sub nameIterator
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{ 
	my ( $rhSelf ) = shift;
	my ( $sID ) = $_[ 0 ] || 0;	
	
	my $rcFunc = sub {
		return $rhSelf->__getEndFlag() if $sID >= $rhSelf->size();
		my $rhMeta = $rhSelf->{ LIST }[ $sID++ ];
		return $rhMeta->getName();
	};
	
	return ListIterator( $rcFunc );
}

sub compare
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{
	my( $rhSelf ) = shift;
	my ( $raValues ) = shift;
	
	return 0 if not $raValues or
				not @{ $raValues };
	
	return 0 if $#{ $raValues }	+ 1 != $rhSelf->size();
	
	foreach ( 0 .. $#{ $raValues } ){
		my $rhMeta = $rhSelf->get( $_ );
		if( not  $rhMeta->equals( $raValues->[ $_ ] )  ){
			return 0;
		}
	}	
	
	return 1;
}


sub toNameList
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{
	my ( $rhSelf ) = shift;
	return () if not $rhSelf->{ LIST } or
				 not @{ $rhSelf->{ LIST } };
				 
	return map { $_->getName() } @{ @{ $rhSelf->{ LIST } } };			 
}	

sub toOrgNameList
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{
	my ( $rhSelf ) = shift;
	return () if not $rhSelf->{ LIST } or
				 not @{ $rhSelf->{ LIST } };
				 
	return map { $_->getOrgName() } @{ $rhSelf->{ LIST } } ;			 
}


sub toString
#*****************************************************************************
# PURPOSE:
# USAGE: 
# PASSED ARGS:
# RETURN ARGS:
# $sError - Fail Error Message
#*****************************************************************************
{
	my( $rhSelf ) = shift;
	my $sValue = "MetaNames ( " . $rhSelf->size()  . " )\n";
	$sValue .= "[ " . join( ", ", $rhSelf->toNameList() ) . " ]\n";
	return $sValue;
}


1
__END__;
